//=============================================================================
// LogStream.hh
// ----------------------------------------------------------------------------
// Stream class to help control reporting of logging info.  Items passed
// to stream can be displayed on cout or put in a file and are filtered
// according to a verbosity scale (i.e. messages below the global verbosity
// setting do not appear).  This lets you sprinkle output liberally throughout
// the code and vary which part of that output is displayed by changing
// a single global parameter.   As a kind of ofstream, LogStream behaves
// like any ordinary stream, minimizing the amount of special behavior 
// that needs to be learned. 
// 
//
// Issues/Todo:
//
// Doesn't handle non-builtin classes (including strings)
//
// Should this, perhaps, inherit from a CBTStream base class?  The idea
// would be to have all streams in the CBT be an instance of CBTStream. 
// That way you can pass in either some specialized stream, like LogStream, 
// or use a normal stream?   As it is, a Print() method that expects 
// an ofstream won't work...right?
// 
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#include <iostream>
#include <fstream>
#include <string>

#ifndef _LOGSTREAM
#define _LOGSTREAM

const int lnever = 0;
const int lerr=1;
const int lwarn=2;
const int lstatus=3;
const int lverbose=99;
const int lalways=100;

const bool usecout=true;
const bool usefile=false;

//-----------------------------------------------------------------------------
// * LogStream
//-----------------------------------------------------------------------------
// 
class LogStream: public ofstream{
public:

  LogStream(int g,bool b){
	 mbUseCout = b;
	 mGlobalVerbosity=g;
  };
  LogStream(){mbUseCout = false;mGlobalVerbosity=0;mCurrentVerbosity=0;};
  ~LogStream(){};

  LogStream& operator()(int LogLevel){
  	 mCurrentVerbosity = LogLevel;
	 return(*this);
  };

  LogStream& operator()(int LogLevel,bool b){
	 mbUseCout = b;
  	 mCurrentVerbosity = LogLevel;
	 return(*this);
  };

  LogStream& operator()(bool b){
	 mbUseCout = b;
	 return(*this);
  };

  // Convenience sugar
  LogStream& error(){
  	 mCurrentVerbosity = lerr;
	 return(*this);
  };

  LogStream& warn(){
  	 mCurrentVerbosity = lwarn;
	 return(*this);
  };

  LogStream& verbose(){
  	 mCurrentVerbosity = lverbose;
	 return(*this);
  };

  LogStream& always(){
  	 mCurrentVerbosity = lalways;
	 return(*this);
  };


  // GlobalVerbosity level setting methods
  void SetGlobalLevel(int a){ 
	 mGlobalVerbosity = a;
  };

  void ShowWarnings(){ 
	 mGlobalVerbosity = lwarn;
  };

  void ShowVerbose(){ 
	 mGlobalVerbosity = lverbose;
  };
  
  void ShowErrors(){ 
	 mGlobalVerbosity = lerr;
  };
  
  void ShowNothing(){ 
	 mGlobalVerbosity = lnever;
  };

  
  void UseCout(){mbUseCout = true;};

  // Conditional output based on verbosity level.
  template<class T> inline LogStream& operator<<(T s){
	 if (mbUseCout){
		if (writeEnabled()) cout<<s;
	 }else{
		if (writeEnabled()) ofstream::operator<<(s);
	 }
	 return(*this);
  };  

  LogStream&  operator<<(LogStream& l){ return(l);};

protected:
  int mGlobalVerbosity;   // Minimum verbosity level that will be shown. 
  int mCurrentVerbosity;     // Current level of output.
  bool mbUseCout;            // Use cout rather than a file

  inline bool writeEnabled(){return(mCurrentVerbosity<=mGlobalVerbosity);};

};


#endif
